package com.qf.kdxf;

/**
 * @Author 明廷盛
 * @Date 2025/6/11 19:57
 * @Description
 */



import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import okhttp3.*;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

public class LLM_OCR {
    // 控制台地址https://console.xfyun.cn/services/se75ocrbm
    public static final String APP_ID = "ced63297";
    public static final String API_SECRET = "MDU2NjU1YzE5OTQ0MDk1NzliNjkzNzY5";
    public static final String API_KEY = "fa3ef253b402aedd87a92676047e5010";
    private static final String HOST = "https://cbm01.cn-huabei-1.xf-yun.com/v1/private/se75ocrbm";
    private static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder()
            .connectTimeout(300, TimeUnit.SECONDS)
            .writeTimeout(300, TimeUnit.SECONDS)
            .readTimeout(300, TimeUnit.SECONDS)
            .build();

    public static void main(String[] args) {
        String imagePath = "C:\\Users\\15943\\Downloads\\ocr.jpg";//测试时写本地文件路径
        try {
            JSONObject result = ocrStatic(imagePath);
            System.out.println("OCR Result:\n" + JSONUtil.toJsonPrettyStr(result));
        } catch (Exception e) {
            System.err.println("OCR Failed: " + e.getMessage());
            e.printStackTrace();
        }
    }


    /**
     * 静态OCR入口方法
     * @param imagePath 图片本地路径
     * @return 结构化OCR结果
     */
    public static JSONObject ocrStatic(String imagePath) throws Exception {
        // 读取并编码图片
        FileData fileData = readImageFile(imagePath);

        // 构建请求体
        String requestJson = buildRequest(APP_ID, 12345L, fileData.base64, fileData.fileType);

        // 执行请求
        String response = executeOCRRequest(requestJson);
        //System.out.println(response);

        return JSONUtil.parseObj(response);
    }


    // 读取图片文件
    private static FileData readImageFile(String path) throws IOException {
        byte[] bytes = Files.readAllBytes(Paths.get(path));
        String base64 = Base64.getEncoder().encodeToString(bytes);
        String fileType = path.substring(path.lastIndexOf(".") + 1);
        return new FileData(base64, fileType);
    }
    private static class FileData {
        String base64;
        String fileType;

        FileData(String base64, String fileType) {
            this.base64 = base64;
            this.fileType = fileType;
        }
    }

    /**
     * 生成用于鉴权的URL,websocket 接口
     *
     * @param requestUrl
     * @param apiKey
     * @param apiSecret
     * @return final requestUrl
     * @method method
     */
    public static String assembleRequestUrl(String requestUrl, String apiKey, String apiSecret, String method) {
        URL url = null;
        String httpRequestUrl = requestUrl.replace("ws://", "http://").replace("wss://", "https://");
        try {
            url = new URL(httpRequestUrl);
            SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
            format.setTimeZone(TimeZone.getTimeZone("GMT"));
            String date = format.format(new Date());
            String host = url.getHost();
            StringBuilder builder = new StringBuilder("host: ").append(host).append("\n").//
                    append("date: ").append(date).append("\n").//
                    append(method).append(" ").append(url.getPath()).append(" HTTP/1.1");
            Charset charset = Charset.forName("UTF-8");
            Mac mac = Mac.getInstance("hmacsha256");
            SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256");
            mac.init(spec);
            byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));
            String sha = Base64.getEncoder().encodeToString(hexDigits);
            String authorization = String.format("hmac username=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);
            String authBase = Base64.getEncoder().encodeToString(authorization.getBytes(charset));
            return String.format("%s?authorization=%s&host=%s&date=%s", requestUrl, URLEncoder.encode(authBase), URLEncoder.encode(host), URLEncoder.encode(date));

        } catch (Exception e) {
            throw new RuntimeException("assemble requestUrl error:" + e.getMessage());
        }
    }


    // 执行网络请求
    private static String executeOCRRequest(String json) throws Exception {
        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = RequestBody.create(mediaType, json);

        String authUrl =  assembleRequestUrl(HOST, API_KEY, API_SECRET, "POST");;
        Request request = new Request.Builder()
                .url(authUrl)
                .post(body)
                .build();
        System.out.println(request.url());
        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                parseResponse(response.body().string());
                throw new IOException("Unexpected code " + response);
            }
            //System.err.println(response);
            System.out.println("headers\n");
            System.out.println(response.headers());


            return parseResponse(response.body().string());
        }
    }

    // 解析响应
    private static String parseResponse(String response) {
        JSONObject respObj = JSONUtil.parseObj(response);
        JSONObject header = respObj.getJSONObject("header");

        if (header.getInt("code") != 0) {
            System.out.println(header.toString());
            throw new RuntimeException("API Error: code is " + header.getStr("code")+", message:"+header.getStr("message"));
        }

        String encodedText = respObj.getJSONObject("payload")
                .getJSONObject("result")
                .getStr("text");

        return new String(Base64.getDecoder().decode(encodedText));
    }

    // 构建请求JSON
    private static String buildRequest(String appId, Long uid, String imageBase64, String fileType) {
        return "{\n" +
                "    \"header\": {\n" +
                "        \"app_id\": \"" + appId + "\",\n" +
                "        \"uid\": \"" + uid + "\",\n" +
                "        \"did\": \"iocr\",\n" +
                "        \"net_type\": \"wifi\",\n" +
                "        \"net_isp\": \"CMCC\",\n" +
                "        \"status\": 0,\n" +
                "        \"request_id\": null,\n" +
                "        \"res_id\": \"\"\n" +
                "    },\n" +
                "    \"parameter\": {\n" +
                "        \"ocr\": {\n" +
                "            \"result_option\": \"normal\",\n" +
                "            \"result_format\": \"json,markdown\",\n" +
                "            \"output_type\": \"one_shot\",\n" +
                "            \"exif_option\": \"1\",\n" +
                "            \"json_element_option\": \"\",\n" +
                "            \"markdown_element_option\": \"watermark=1,page_header=1,page_footer=1,page_number=1,graph=1\",\n" +
                "            \"sed_element_option\": \"watermark=0,page_header=0,page_footer=0,page_number=0,graph=0\",\n" +
                "            \"alpha_option\": \"0\",\n" +
                "            \"rotation_min_angle\": 5,\n" +
                "            \"result\": {\n" +
                "                \"encoding\": \"utf8\",\n" +
                "                \"compress\": \"raw\",\n" +
                "                \"format\": \"plain\"\n" +
                "            }\n" +
                "        }\n" +
                "    },\n" +
                "    \"payload\": {\n" +
                "        \"image\": {\n" +
//                "            \"encoding\": \"" + fileType + "\",\n" +
                "            \"image\": \"" + imageBase64 + "\"\n" +
//                "            \"status\": 0,\n" +
//                "            \"seq\": 0\n" +
                "        }\n" +
                "    }\n" +
                "}";
    }


}
